package com.hsqyz.esp32_led.netty.codec;

import com.hsqyz.esp32_led.model.dto.Esp32MessageDto;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.util.CharsetUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * ESP32消息编解码器
 * 
 * 该类负责处理ESP32设备与服务器之间的消息编解码工作，主要功能包括：
 * 1. 消息编码：将Esp32MessageDto对象转换为网络传输的字节流
 * 2. 消息解码：将接收到的字节流转换为Esp32MessageDto对象
 * 
 * 使用MessageToMessageCodec实现，支持双向编解码
 * 使用@ChannelHandler.Sharable注解，允许多个Channel共享同一个编解码器实例
 */
@Slf4j
@RequiredArgsConstructor
@ChannelHandler.Sharable
public class Esp32MessageCodec extends MessageToMessageCodec<ByteBuf, Esp32MessageDto> {

    /**
     * 报文协议的固定魔数，用于标识消息类型
     */
    public static final int MAGIC_NUM = 0xEE;
    public static final String MAGIC_NUM_STR = "EE";

    /**
     * 消息编码方法
     * 
     * 将Esp32MessageDto对象编码为字节流，准备进行网络传输。
     * 编码过程包括：
     * 1. 分配缓冲区
     * 2. 写入消息内容
     * 3. 将编码后的数据添加到输出列表
     *
     * @param channelHandlerContext 通道上下文，提供与通道交互的方法
     * @param nettyMessageDto 待编码的消息对象
     * @param list 用于存储编码后的消息的列表
     * @throws Exception 编码过程中可能发生的异常
     */
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Esp32MessageDto nettyMessageDto, List<Object> list) throws Exception {
        // 记录开始编码消息的日志
        log.info("=============== 开始编码消息 ===============");

        // 分配缓冲区用于消息编码
        ByteBuf out = channelHandlerContext.alloc().buffer();

        // 记录编码前的消息内容，用于调试和日志记录
        log.info("================================ CMD：{},命令发送", nettyMessageDto.getCmd());
        log.info("发送信息内容：{}", nettyMessageDto.getCmd());

        // 将消息内容编码为字节并写入缓冲区
        out.writeBytes(nettyMessageDto.getCmd().getBytes());

        // 将编码后的消息添加到输出列表
        list.add(out);
    }

    /**
     * 消息解码方法
     * 
     * 将接收到的字节流解码为Esp32MessageDto对象。
     * 解码过程包括：
     * 1. 读取字节流内容
     * 2. 转换为字符串
     * 3. 构建消息对象
     * 4. 将解码后的对象添加到输出列表
     *
     * @param channelHandlerContext 通道上下文，提供与通道交互的方法
     * @param byteBuf 待解码的字节缓冲区
     * @param list 用于存储解码后的消息的列表
     * @throws Exception 解码过程中可能发生的异常
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        // 记录开始解码消息的日志
        log.info("=============== 开始解码消息 ===============");
        log.info("clientId:{}", channelHandlerContext.channel().id().asLongText());
        log.info("channelId:{}", channelHandlerContext.channel().id());

        // 将字节流转换为字符串
        String cmd = byteBuf.toString(CharsetUtil.UTF_8);

        // 构建消息对象
        Esp32MessageDto messageDto = Esp32MessageDto.builder().cmd(cmd).build();

        // 将解码后的消息对象添加到输出列表
        list.add(messageDto);
    }
}